package com.akina.matchsystem.service.impl;

import com.akina.matchsystem.common.ErrorCode;
import com.akina.matchsystem.exception.BusinessException;
import com.akina.matchsystem.model.domain.User;
import com.akina.matchsystem.model.domain.UserTeam;
import com.akina.matchsystem.model.dto.TeamQuery;
import com.akina.matchsystem.model.enums.TeamStatusEnums;
import com.akina.matchsystem.model.request.TeamJoinRequest;
import com.akina.matchsystem.model.request.TeamQuitRequest;
import com.akina.matchsystem.model.request.TeamUpdateRequest;
import com.akina.matchsystem.model.vo.TeamUserVO;
import com.akina.matchsystem.model.vo.UserVO;
import com.akina.matchsystem.service.UserService;
import com.akina.matchsystem.service.UserTeamService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.akina.matchsystem.model.domain.Team;
import com.akina.matchsystem.mapper.TeamMapper;
import com.akina.matchsystem.service.TeamService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.CalendarUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
* @author 浪子心声
* @description 针对表【team(队伍)】的数据库操作Service实现
* @createDate 2024-03-21 08:56:08
*/
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
    implements TeamService{

    @Resource
    UserTeamService userTeamService;
    @Resource
    UserService userService;

    @Resource
    RedissonClient redissonClient;

    /**
     * 创建队伍
     * @param team
     * @param loginUser
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)//指定异常类，事务出问题抛哪个异常
    public long addTeam(Team team, User loginUser) {
        /**
         *业务流程
         1.请求参数是否为空?
         2.是否登录，未登录不允许创建
         3.校验信息
            1.队伍人数>1目:= 20
            2.队伍标题 <= 20
            3.描述 <= 512
            4.是否公开 0
            5.密码 <= 32
            6.超过时间大于当前时间
         4.插入队伍信息到队伍表
         5.插入用户到队伍表
         */
        //1请求参数
        if(team == null) {
            throw  new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //2用户是否登录
        if(loginUser==null){
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        final long UserId=loginUser.getId();
        //3校验信息 1.队伍人数设置>1目<= 20
        Integer maxNum = team.getMaxNum();
        if(maxNum<=1||maxNum>20){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍人数错误");
        }
        //3.2队伍标题
        String teamName = team.getName();
        if(StringUtils.isBlank(teamName)||teamName.length()>20){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍名字不符规范");
        }
        //3.3   描述<=512
        String description= team.getDescription();
        if (StringUtils.isNotBlank(description)&&description.length()>512){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍描述不符合要求");
        }
        //3.4 status是否公开（int）不传默认为0，公开  0 1 2加密
        /*Integer statusTeam = team.getStatus();
        if(statusTeam==null)team.setStatus(1);*/
        //这个的作用就是，空的话就默认为orElse。
        int status = Optional.ofNullable(team.getStatus()).orElse(0);
        TeamStatusEnums teamStatusEnums = TeamStatusEnums.getStatus(status);
        if(teamStatusEnums==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍状态错误");
        }
        //3.5 如果是加密       密码 <= 32

        if(teamStatusEnums.getValue()==2){
            String teamPassword = team.getPassword();
            if(StringUtils.isBlank(teamPassword)||teamPassword.length()>32){
                throw  new BusinessException(ErrorCode.PARAMS_ERROR,"用户密码错误");
            }
        }

        //  3.6     .超过时间大于创建时间
        if(new Date().after(team.getExpireTime())){
            //超时后
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "超时时间 > 当前时间");
        }
        // 3.7      校验用户所创建队伍最多为5个
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId", UserId);
        //统计 用count函数
        long countTeam = this.count(queryWrapper);
        if(countTeam>=5){//有五个就不能创建了
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户最多创建5个队伍");
        }
        //4插入队伍信息到队伍表
        //要把队伍id给置空，让保存的时候自增
        team.setId(null);
        team.setUserId(UserId);
        boolean save = this.save(team);
        Long teamId=team.getId();
        if(!save||teamId==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"创建队伍失败");
        }
        //5插入用户信息到用户队伍关系表  这里保证原子性用了事务的注解。
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(UserId);
        userTeam.setTeamId(team.getId());
        userTeam.setJoinTime(new Date());

        save = userTeamService.save(userTeam);
        if(!save){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"创建队伍失败");
        }
        return teamId;
    }

    @Override
    public List<TeamUserVO> listTeam(TeamQuery teamQuery,boolean isAdmin) {
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        //组合查询条件
        if(teamQuery!=null){
            Long id = teamQuery.getId();
            if(id!=null&&id>0){
                queryWrapper.eq("id",id);
            }
            //id列表里都加入查询
            List<Long> idList = teamQuery.getIdList();
            if(CollectionUtils.isNotEmpty(idList)){
                queryWrapper.in("id",idList);
            }

            String searchText = teamQuery.getSearchText();
            if(StringUtils.isNotBlank(searchText)){
                queryWrapper.and(qw->qw.like("name",searchText ).or().like("description", searchText) );//这里能模糊查询名字和描述
            }
            String name = teamQuery.getName();
            if(name!=null){
                queryWrapper.eq("name", name);
            }
            String description = teamQuery.getDescription();
            if(StringUtils.isNotBlank(description)){
                queryWrapper.like("description", description);//这里就能模糊查询了
            }
            //根据创建人搜索
            Long userId = teamQuery.getUserId();
            if(userId!=null&&userId>0){
                queryWrapper.eq("userId", userId);
            }
            //根据状态查询，  只有管理员才能看加密的房间。
            Integer status = teamQuery.getStatus();
            TeamStatusEnums statusEnums = TeamStatusEnums.getStatus(status);
            if(statusEnums==null){
                //默认为公开
                statusEnums =TeamStatusEnums.PUBLIC;
            }
            if(!isAdmin&&statusEnums.equals(TeamStatusEnums.PRIVATE)){
                //只有管理员才能搜索私密状态
                throw new BusinessException(ErrorCode.NO_AUTH);
            }
            queryWrapper.eq("status", statusEnums.getValue());//数字对应

        }
        List<Team> teamList1 = this.list(queryWrapper);
        //关联查询用户信息
        if(CollectionUtils.isEmpty(teamList1)){
            //如果为空
            return  new ArrayList<>();
        }
        //关联查询创建人用户信息，自己写sql，用主表（必有）left join 从表（可有）on condition ，
        //select * from team t left join user u on t.userId=u.Id
        //查询队伍，以及加入成员的信息
        //select * from team t join user_team ut on t.Id=ut.teamId
        // 不展示已过期的队伍
        // expireTime is null or expireTime > now()
        queryWrapper.and(qw -> qw.gt("expireTime", new Date()).or().isNull("expireTime"));
        //关联创建人的用户信息
        List<TeamUserVO> teamUserVOList = new ArrayList<>();
        for (Team team : teamList1){
            Long userId = team.getUserId();
            if(userId==null){
                continue;
            }
            TeamUserVO teamUserVO = new TeamUserVO();
            BeanUtils.copyProperties(team, teamUserVO);
            User user = userService.getById(userId);
            // 对用户信息脱敏
            //User safetyUser = userService.getSafetyUser(user);
            if(user != null){
            UserVO userVO =new UserVO();
            BeanUtils.copyProperties(user,userVO );
            teamUserVO.setUserCreate(userVO);
            }
            teamUserVOList.add(teamUserVO);
        }

        return teamUserVOList;
    }

    @Override
    public boolean updateTeam(TeamUpdateRequest teamUpdateRequest,User loginUser) {
       if(teamUpdateRequest == null){
           throw new BusinessException(ErrorCode.PARAMS_ERROR);
       }
        Long id = teamUpdateRequest.getId();
       if(id==null||id<=0){
           throw  new BusinessException(ErrorCode.PARAMS_ERROR);
       }
       //根据id获取旧的队伍
       Team oldteam = this.getById(id);
       if(oldteam==null){
           throw  new BusinessException(ErrorCode.PARAMS_ERROR,"队伍不存在");
       }
        //判断用户是否为管理员或者创建者

       if(oldteam.getUserId()!=loginUser.getId()&&userService.isAdmin(loginUser)){
           throw new BusinessException(ErrorCode.NO_AUTH);
       }
       //如果修改房间的私密性，如果队伍状态为加密，则要输入密码
        TeamStatusEnums statusEnums = TeamStatusEnums.getStatus(oldteam.getStatus());
       if(statusEnums.equals(TeamStatusEnums.SECRET)){
            if(StringUtils.isBlank(teamUpdateRequest.getPassword())){
                //如果没传递密码
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"加密房间必须有密码");
            }

       }
       Team teamUpdate = new Team();
       BeanUtils.copyProperties(teamUpdateRequest, teamUpdate);
        boolean result = this.updateById(teamUpdate);//ById不用加查询条件，自动比对id
        return result;
    }

    @Override
    public boolean joinTeam(TeamJoinRequest teamJoinRequest,User loginUser) {
        if(teamJoinRequest==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long teamId = teamJoinRequest.getTeamId();
        Team team = this.getById(teamId);
        if(team==null){
            throw  new BusinessException(ErrorCode.NULL_ERROR,"队伍不存在");
        }
        Date expireTime = team.getExpireTime();
        if(expireTime !=null&&new Date().after(expireTime)){
            //队伍过期了
            throw new BusinessException(ErrorCode.NULL_ERROR,"队伍已过期");
        }
        Integer teamStatus = team.getStatus();
        TeamStatusEnums teamStatusEnums = TeamStatusEnums.getStatus(teamStatus);
        if(TeamStatusEnums.PRIVATE.equals(teamStatusEnums)){
            throw new BusinessException(ErrorCode.NO_AUTH,"禁止加入私密队伍");
        }
        String password = teamJoinRequest.getPassword();
        if(TeamStatusEnums.SECRET.equals(teamStatusEnums)){
            if(StringUtils.isBlank(password)||!password.equals(team.getPassword()))
            {
                throw new BusinessException(ErrorCode.NULL_ERROR,"密码错误");
            }
        }

        //查询用户已加入队伍数量
        long userId = loginUser.getId();
        //通过count和用户关联表来查询用户加入队伍数量<5
        RLock lock = redissonClient.getLock("lock:akina_join:");
        UserTeam userTeam;
        try {
            //抢锁
            while(true) {
                if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) {

                    QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("userId", userId);
                    long isJoinNum = userTeamService.count(queryWrapper);
                    if (isJoinNum > 5) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "最多加入五个队伍");
                    }

                    //不能重复加入队伍
                    queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("userId", userId);
                    queryWrapper.eq("teamId", teamId);
                    long hasJoinTeam = userTeamService.count(queryWrapper);
                    if (hasJoinTeam > 0) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "该用户已加入该队伍");
                    }
                    //已加队伍的人数

                    long teamHasJoinNum = this.countTeamUserByTeamId(teamId);//封装方法了，返回队伍人数
                    if (teamHasJoinNum >= team.getMaxNum()) {
                        throw new BusinessException(ErrorCode.NULL_ERROR, "队伍人数已满");
                    }
                    //  新增用户队伍信息
                    userTeam = new UserTeam();
                    userTeam.setUserId(userId);
                    userTeam.setTeamId(teamId);
                    userTeam.setJoinTime(new Date());
                    return userTeamService.save(userTeam);
                }
            }
            } catch (InterruptedException e) {
            log.error("CacheRecommendUser error",e);
            return false;
        } finally {
            if(lock.isHeldByCurrentThread()){//释放自己的锁
                System.out.println("unlock"+Thread.currentThread().getId());
                lock.unlock();
            }
        }

    }

    /**
     * 退出队伍
     * @param teamQuitRequest
     * @param userLogin
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean quitTeam(TeamQuitRequest teamQuitRequest, User userLogin) {
        if(teamQuitRequest==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

       /* Long teamId = teamQuitRequest.getTeamId();
        if(teamId==null||teamId<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team team = this.getById(teamId);
        if(team==null){
            throw new BusinessException(ErrorCode.NULL_ERROR,"队伍不存在");
        }*/
        //获取队伍信息
        Long teamId = teamQuitRequest.getTeamId();
        Team team = getTeamById(teamId);
        long userId = userLogin.getId();
        UserTeam queryUserTeam = new UserTeam();
        queryUserTeam.setTeamId(teamId);
        queryUserTeam.setUserId(userId);
        //这里查询符合条件的关系
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>(queryUserTeam);
        long count = userTeamService.count(queryWrapper);
        if(count==0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"未加入队伍");
        }
        long teamHasJoinNum = this.countTeamUserByTeamId(teamId);
        //对位里人数量
        if(teamHasJoinNum==1){
            //删除队伍和所有加入队伍的关系
           /* QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
            userTeamQueryWrapper.eq("teamId", teamId);
             boolean remove = userTeamService.remove(userTeamQueryWrapper);*/
            this.removeById(teamId);
        }else{
            //看是否为队长，队长退出队长顺位
            if(team.getUserId()==userId){
                //如果是队长
                //查询已加入队伍的所有用户和加入时间
                QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
                userTeamQueryWrapper.eq("teamId", teamId);
                userTeamQueryWrapper.last("order by id asc limit 2");//把按id排序
                List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);
                if(CollectionUtils.isEmpty(userTeamList)||userTeamList.size()<=1){
                    //队伍少于2个人就抛出异常
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                }
                UserTeam nextUserTeam = userTeamList.get(1);//获得第二个用户
                //更新队伍的队长
                Long leaderId= nextUserTeam.getUserId();
                Team updateTeam = new Team();
                updateTeam.setUserId(leaderId);
                boolean update = this.updateById(updateTeam);
                //删除退出的用户关系
                if(!update){
                    throw new BusinessException(ErrorCode.NULL_ERROR,"更新队长失败");
                }
               /* userTeamQueryWrapper = new QueryWrapper<>();
                userTeamQueryWrapper.eq("teamId", teamId);
                userTeamQueryWrapper.eq("userId", userId);*/
                //移除队伍里老队长的队伍用户关系 这个wrapper在前面有好像，等于上面逻辑

            }
        }
        return  userTeamService.remove(queryWrapper);
    }

    /**
     * 删除队伍（队长）
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteTeam(Long id,User loginUser) {
        //校验队伍是否存在
        Team team = getTeamById(id);
        long teamId = team.getId();
        //校验用户是否为队长
        if(loginUser==null){
            throw  new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if(loginUser.getId()!=team.getUserId()){
            throw new BusinessException(ErrorCode.NO_AUTH,"没有权限");
        }
        //移除所有人加入队伍的关联信息
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("teamId", teamId);
        boolean res = userTeamService.remove(queryWrapper);
        if(!res){
            throw new BusinessException(ErrorCode.NULL_ERROR,"删除队伍失败");
        }
        //删除队伍
        boolean result = this.removeById(teamId);

        return result;
    }
    /**
     * 根据 id 获取队伍信息
     *
     * @param teamId
     * @return
     */
    private Team getTeamById(Long teamId) {
        if (teamId == null || teamId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team team = this.getById(teamId);
        if (team == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "队伍不存在");
        }
        return team;
    }

    /**
     * 获取某队伍当前人数
     *
     * @param teamId
     * @return
     */
    private long countTeamUserByTeamId(long teamId) {
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("teamId", teamId);
        return userTeamService.count(userTeamQueryWrapper);
    }

}




